package com.stu.info;

import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;

import android.graphics.PointF;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.stu.aq.*;
import com.stu.graph.*;
import com.stu.usb.SerialIOManager;
import com.stu.widget.GraphView;

public class AltitudeGraphFragment extends GraphFragment implements SerialIOManager.Listener {
	private int xValue;
	private Timer timer;
	private boolean isAlive;
	private boolean stopFlag;
	private StatusManager statusManager;
	private String statusStr;

	private class Status {
		public float	barometer, range;
	}

	public AltitudeGraphFragment() {
		xValue = 0;
		initData();
		statusManager = new StatusManager();
	}

	private void initData() {
		graphSeries = new ArrayList<DataSeries>(AQ.Altitude.COUNT);
		graphSeries.add( AQ.Altitude.BAROMETER, new DataSeries("Barometer", new DataStyle(AQ.Colors[0], 3)) );
		graphSeries.add( AQ.Altitude.RANGE, new DataSeries("Range Finder", new DataStyle(AQ.Colors[1], 3)) );
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
	  Bundle savedInstanceState) {
		View v = inflater.inflate( R.layout.graph, container, false );
		init( v, "Altitude Data", 50, GraphView.GraphViewConfig.GRID_Y, 50, 50 );
		updateViews();
		return v;
	}

	@Override
	public void onDestroyView() {
		super.onDestroyView();
		if( timer != null )
			timer.cancel();
	}
	
	/*
	 * 0 Barometer
	 * 1 Range Finder
	 */
	@Override
	public void onNewData(byte[] data) {
if(AQ.DEBUG) Log.d("altitude", "onNewData");
		isAlive = true;
		if( statusStr == null )
			statusStr = new String( data );
		else
			statusStr += new String( data );
		if( stopFlag ) {
if(AQ.DEBUG) Log.d("altitude", "onNewData stop");
			statusStr = null;
			return;
		}
		// make sure we have the entire status by
		//  looking for a newline at the end
		int ix = statusStr.length();
		if( statusStr.charAt(ix-1) != '\n' )
			return;
		statusStr = statusStr.trim();	// remove newline and trailing spaces
		ix = statusStr.length();
		// don't include trailing comma in substring
		if( statusStr.charAt(ix-1) == ',' )
			ix--;
		final String values[] = statusStr.substring(0, ix).split( "," );
		if( values.length != AQ.Altitude.COUNT ) {
			statusStr = null;
			mListener.OnCommandWarning( getId(), new AQException(AltitudeGraphFragment.class.getSimpleName() +
			  ": Expected length " + String.valueOf(AQ.Altitude.COUNT) + " got " + String.valueOf(values.length)) );
			return;
		}
		Status s = new Status();
		try {
			s.barometer = Float.parseFloat( values[0] );
			s.range = Float.parseFloat( values[1] );
		} catch( NumberFormatException e ) {
			mListener.OnCommandError( getId(), new AQException(AltitudeGraphFragment.class.getSimpleName() +
			  ": NumberFormatException: " + e.getMessage()) );
			statusStr = null;
			return;
		}
		statusStr = null;
		statusManager.handleState( new StatusData(this, s) );
	}

	@Override
	public void onRunError(Exception e) {
	}

	@Override
	public void update(OnCommandListener l, SerialIOManager io) {
if(AQ.DEBUG) Log.d("altitude", "update");
		xValue = 0;
		if( graphSeries == null )
			initData();		// in case clear() was called
		mListener = l;
		stopFlag = false;
		isAlive = false;
		io.setListener( this );
	    String s = "z";
	    io.writeAsync( s.getBytes() );
		// Make sure we are getting status
		timer = new Timer();
		TimerTask tt = new TimerTask() {
			@Override
			public void run() {
				checkIfAlive();
				isAlive = false;
			}
		};
		timer.scheduleAtFixedRate( tt, 1000, 1000 );
	}

	private void checkIfAlive() {
		if( !isAlive ) {
			timer.cancel();
			if( mListener != null )
				mListener.OnCommandError( getId(), new AQException("No altitude data from AeroQuad") );
		}
	}

	@Override
	public void updateUI(Object statusData) {
		if( statusData != null && graphSeries != null ) {
			Status s = (Status)statusData;
			graphSeries.get(AQ.Altitude.BAROMETER).appendData( new PointF(xValue, s.barometer) );
			graphSeries.get(AQ.Altitude.RANGE).appendData( new PointF(xValue, s.range) );
			updateViews();
			xValue++;
		}
		mListener.OnCommandComplete( getId(), FragmentState.UPDATING );
	}

	@Override
	public void stopUpdate(OnCommandListener l, SerialIOManager io) {
if(AQ.DEBUG) Log.d("altitude", "stopUpdate");
		mListener = l;
		stopFlag = true;
		timer.cancel();
		io.setListener( this );
	    String s = "x";
	    io.writeAsync( s.getBytes() );
	    // onNewData and updateUI may not be called, depending on
	    //  what still remains in the IO buffer so call the listener here
		mListener.OnCommandComplete( getId(), FragmentState.STOPPING );
	}

	@Override
	public void clear() {
		super.clear();
		graphSeries = null;
	}
}
